打包优化:加入directives指令&外置依赖减小包体积
概述
组件库项目除了导出 Components 和 Composition API(hooks/composables)之外,还包含自定义指令(directives)部分。本节介绍如何将指令模块整合到组件库的打包导出中,以及通过外置依赖(external dependencies)来减小包体积。
需要导出的模块全景
组件库导出内容:
├── components/ # 组件(已在前面处理)
├── composables/ # 组合式函数 / hooks(已在前面处理)
├── directives/ # 自定义指令(本节重点)
└── utils/ # 工具函数(通常不单独导出)
text
步骤一:整合 Directives 到组件库
1. 复制指令目录
将 admin 项目中的 src/directives 目录复制到组件库项目的 src/ 下:
# 项目结构
src/
├── components/
├── composables/
├── directives/ # 自定义指令
│ ├── index.ts # 入口文件(包含 setupDirectives)
│ ├── copy.ts # 复制指令
│ ├── debounce.ts # 防抖指令
│ ├── throttle.ts # 节流指令
│ ├── permission.ts # 权限指令
│ └── scrollText.ts # 滚动文字指令
└── index.ts # 组件库主入口
bash
2. 入口文件导出指令
// src/main.ts — 组件库主入口
import type { App } from 'vue'
// 导入组件注册
import { setupComponents } from './components'
// 导入指令注册
import { setupDirectives } from './directives'
// 导出所有组件和组合式函数
export * from './components'
export * from './composables'
export { setupDirectives } from './directives'
// 默认导出:Vue 插件安装函数
export default {
install(app: App) {
// 组件全局注册
setupComponents(app)
// 指令全局加载
setupDirectives(app)
},
}
ts
3. 指令入口文件结构
// src/directives/index.ts
import type { App } from 'vue'
import { vCopy } from './copy'
import { vDebounce } from './debounce'
import { vThrottle } from './throttle'
import { vPermission } from './permission'
import { vScrollText } from './scrollText'
// 所有指令集合
const directives = {
copy: vCopy,
debounce: vDebounce,
throttle: vThrottle,
permission: vPermission,
scrollText: vScrollText,
}
// 全局注册所有指令
export function setupDirectives(app: App) {
Object.entries(directives).forEach(([name, directive]) => {
app.directive(name, directive)
})
}
// 也支持单独导出各个指令,供按需引入使用
export { vCopy, vDebounce, vThrottle, vPermission, vScrollText }
ts
4. 用户使用方式
// 方式一:全局注册(全量引入)
import VpComponents from '@toimc/vp-components'
app.use(VpComponents)
// 方式二:仅注册指令
import { setupDirectives } from '@toimc/vp-components'
setupDirectives(app)
// 方式三:按需注册单个指令
import { vCopy } from '@toimc/vp-components'
app.directive('copy', vCopy)
ts
步骤二:外置依赖减小包体积
为什么需要外置依赖
组件库打包时,如果不外置第三方依赖(如 Vue、Element Plus),会导致:
- 包体积膨胀 — 重复打包框架代码
- 版本冲突 — 用户项目的 Vue 版本与组件库内部打包的不一致
- 构建变慢 — 每次都要处理大量第三方代码
Vite 库模式外置配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: './src/main.ts',
name: 'VpComponents',
formats: ['es', 'cjs'],
fileName: (format) => `vp-components.${format}.js`,
},
rollupOptions: {
// 外置不需要打包的依赖
external: [
'vue',
'vue-router',
'element-plus',
'@element-plus/icons-vue',
'axios',
'echarts',
],
output: {
// 保留外部依赖的 import 语句
globals: {
vue: 'Vue',
'vue-router': 'VueRouter',
'element-plus': 'ElementPlus',
},
},
},
},
})
ts
package.json 配置
{
"name": "@toimc/vp-components",
"version": "1.0.0",
"type": "module",
"main": "./dist/vp-components.cjs.js",
"module": "./dist/vp-components.es.js",
"exports": {
".": {
"import": "./dist/vp-components.es.js",
"require": "./dist/vp-components.cjs.js"
},
"./style.css": "./dist/style.css"
},
"peerDependencies": {
"vue": "^3.3.0",
"element-plus": "^2.5.0"
},
"dependencies": {},
"devDependencies": {
"vue": "^3.4.0",
"element-plus": "^2.5.0"
}
}
json
关键点:外置的依赖必须声明为
peerDependencies,表示使用方需要自行安装这些依赖。
打包产物分析
外置前后对比
外置前(包含 vue + element-plus):
vp-components.es.js → 350KB+
外置后(仅包含自身代码):
vp-components.es.js → 45KB
style.css → 28KB
text
使用 rollup-plugin-visualizer 分析包体积
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
vue(),
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/stats.html',
}),
],
})
ts
Utils 是否需要导出
// 通常不单独导出 utils 的原因:
// 1. 里面的方法都是基础方法,针对自身组件编写
// 2. 方法较为简单,不值得作为独立模块发布
// 3. 如果足够复杂,可以单独封装为共享库(如 @toimc/shared)
// 例外情况:如果 utils 足够通用,可单独发包
// packages/
// ├── shared/ # 共享工具库
// ├── components/ # 组件库
// └── admin-template/ # 业务项目
ts
实践要点
- 组件库除了导出组件和 hooks,还需整合自定义指令(directives)到导出链路中
- 使用
app.directive(name, directive)全局注册指令,或支持按需单独引入 - 组件库打包时必须外置 Vue、Element Plus 等核心依赖,避免包体积膨胀和版本冲突
- 外置的依赖须在
package.json的peerDependencies中声明 - 使用
rollup-plugin-visualizer分析打包产物,找出体积瓶颈 - Utils 工具函数除非足够通用,否则不单独导出;复杂场景可拆分为独立共享包
↑